package ooo.reindeer.commons.utils.queue;

import java.util.concurrent.DelayQueue;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;

public class SimpleDelayQueue<T> {

    DelayQueue<DelayItem<T>> queue;

    private int delayTime;

    public SimpleDelayQueue(int delayTime) {
        queue = new DelayQueue<DelayItem<T>>();
        this.delayTime = delayTime;
    }

    public SimpleDelayQueue() {
        this(0);
    }

    public DelayItem<T> put(T value) {
        return put(new DelayItem<T>(delayTime,
                value));
    }

    public DelayItem<T> put(T value, long delayTime, TimeUnit unit) {
        return put(new DelayItem<T>(TimeUnit.MILLISECONDS.convert(delayTime, unit), value));
    }

    public DelayItem<T> put(DelayItem<T> item) {
        queue.add(item);
        return item;
    }

    public DelayItem<T> remove(DelayItem<T> item) {

        if (queue.remove(item)) {
            return item;
        } else {
            return null;
        }
    }

    public T take() {

        try {

            DelayItem<T> delayItem = queue.take();
            return delayItem.getValue();

        } catch (InterruptedException e) {
            //no thing to do
        }
        return null;
    }

    public DelayItem<T> takeOriginal() {

        try {

            DelayItem<T> delayItem = queue.take();
            return delayItem;

        } catch (InterruptedException e) {
            //no thing to do
        }
        return null;
    }

    public static class DelayItem<T> implements Delayed {

        private long timePoint;

        private T value;

        DelayItem(T value) {
            this.value = value;

        }

        public DelayItem(long time_out, T value) {
            this.value = value;
            timePoint = System.currentTimeMillis() + time_out;
        }

        public int compareTo(Delayed o) {
            if (getDelay(TimeUnit.MILLISECONDS) > o.getDelay(TimeUnit.MILLISECONDS)) return 1;
            if (getDelay(TimeUnit.MILLISECONDS) < o.getDelay(TimeUnit.MILLISECONDS)) return -1;
            return 0;
        }

        public long getDelay(TimeUnit unit) {
            long delay = unit.convert(timePoint - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
            return delay;
        }

        public T getValue() {
            return value;
        }

        public void setTimeOut(long time_out) {
            timePoint = System.currentTimeMillis() + time_out;
        }

    }

}
